package com.wuercloud.mq.config;

import com.wuercloud.mq.message.converter.FastJsonMessageConverter;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitManagementTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by JiangWL on 2017/3/8.
 */
@Configuration
@ComponentScan("com.wuercloud.mq")
@PropertySource(value = "classpath:mq/rabbitmq-conf.properties",ignoreResourceNotFound = true)
public class RabbitmqConfiguration {
    @Autowired
    private Environment environment;

    @Bean("restClientTemplate")
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Bean
    public FastJsonMessageConverter fastJsonMessageConverter(){
        return new FastJsonMessageConverter();
    }


    /**
     * rabbitmq管理器，可以对队列进行管理，调用其rest
     * @return
     */
    @Bean
    public RabbitManagementTemplate rabbitManagementTemplate() {
        RabbitManagementTemplate rabbitManagementTemplate = new RabbitManagementTemplate(
                environment.getProperty("rabbitmq-manage-url"),
                environment.getProperty("rabbitmq-Username"),
                environment.getProperty("rabbitmq-Password"));
        return rabbitManagementTemplate;
    }

    @Bean("rabbitConnectionFactory")
    public ConnectionFactory rabbitConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(environment.getProperty("rabbitmq-Address"));
        connectionFactory.setVirtualHost(environment.getProperty("rabbitmq-VirtualHost"));
        connectionFactory.setUsername(environment.getProperty("rabbitmq-Username"));
        connectionFactory.setPassword(environment.getProperty("rabbitmq-Password"));
        //设置为手工确认模式
        connectionFactory.setPublisherConfirms(true);
        connectionFactory.setPublisherReturns(true);
        ExecutorService service = Executors.newFixedThreadPool(Integer.parseInt(environment.getProperty("rabbitmq-fixThreadNums")));
        connectionFactory.setExecutor(service);
        connectionFactory.setConnectionTimeout(30000);
        //connectionFactory.setChannelCacheSize(Runtime.getRuntime().availableProcessors());
        connectionFactory.setChannelCacheSize(Integer.parseInt(environment.getProperty("rabbitmq-ChannelCacheSize")));
        //线程池
        connectionFactory.setConnectionThreadFactory(new CustomizableThreadFactory(environment.getProperty("rabbitmq-ThreadNamePrefix")));
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin() {
        return new RabbitAdmin(rabbitConnectionFactory());
    }

    /**
     * 失败重试发送模板，其他template需用时要注入此bean
     * 如：template.setRetryTemplate(retryTemplate);
     * retryTemplate需要在业务类中@Autowired
     * @return
     */
    @Bean
    public RetryTemplate retryTemplate(){
        RetryTemplate retryTemplate = new RetryTemplate(){
            @Override
            public void setBackOffPolicy(BackOffPolicy backOffPolicy) {
                ExponentialBackOffPolicy policy = new ExponentialBackOffPolicy();
                /*
                    失败重试机制，发送失败之后，会尝试重发三次，重发间隔(ms)为
                    第一次 initialInterval
                    此后：initialInterval*multiplier > maxInterval ? maxInterval : initialInterval*multiplier。
                    配合集群使用的时候，当mq集群中一个down掉之后，重试机制尝试其他可用的mq。
                    API默认为：
                        private volatile long initialInterval = 100L;
                        private volatile long maxInterval = 30000L;
                        private volatile double multiplier = 2.0D;
                */
                policy.setInitialInterval(Integer.parseInt(environment.getProperty("backOffPolicy.initialInterval")));
                policy.setMultiplier(Integer.parseInt(environment.getProperty("backOffPolicy.multiplier")));
                policy.setMaxInterval(Integer.parseInt(environment.getProperty("backOffPolicy.maxInterval")));

            }
        };
        return retryTemplate;
    }

}
